/*=====================================================
Critical Links
Auto Configuration Server

Authors:
	Rui Eduardo Gouveia Gil - r-gil@critical-links.com

Date: 2010
Version 0.1
=======================================================*/
#ifndef __HTTPFILESERVICE_H__
#define __HTTPFILESERVICE_H__

#include <map>
#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <pion/PionPlugin.hpp>
#include <rgcpp/structs/Map.h>
#include <boost/shared_ptr.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_array.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/functional/hash.hpp>
#include <boost/filesystem/path.hpp>
#include <rgcpp/net/http/MIMETypes.h>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <rgcpp/exceptions/IOException.h>
#include <rgcpp/exceptions/RuntimeException.h>
#include <boost/algorithm/string/case_conv.hpp>

#include "httpd/DiskFileSender.h"

#define DEFAULT_CACHE_SETTING 1
#define DEFAULT_SCAN_SETTING 0
#define DEFAULT_MAX_CACHE_SIZE 0
#define DEFAULT_MAX_CHUNK_SIZE 0

namespace acs
{

enum ResponseType
{
	RESPONSE_UNDEFINED,		// initial state until we know how to respond
	RESPONSE_OK,			// normal response that includes the file's content
	RESPONSE_HEAD_OK,		// response to HEAD request (would send file's content)
	RESPONSE_NOT_FOUND,		// Not Found (404)
	RESPONSE_NOT_MODIFIED	// Not Modified (304) response to If-Modified-Since
};

class HttpFileService : public pion::net::WebService
{
	private:
		bool writable;
		boost::mutex cacheMutex;
		unsigned int scanSetting;
		unsigned int cacheSetting;
		unsigned long maxCacheSize;
		unsigned long maxChunkSize;
		boost::filesystem::path file;
		boost::filesystem::path directory;
		rgcpp::Map<std::string,DiskFile> cacheMap;

	public:
		HttpFileService();
		virtual ~HttpFileService();

		virtual void setOption(const std::string& name, const std::string& value);

		virtual void operator()(pion::net::HTTPRequestPtr& request, pion::net::TCPConnectionPtr& tcpConn);

		virtual void start(void);
		virtual void stop(void);

	private:
		void scanDirectory(const boost::filesystem::path& dirPath);
		std::pair<rgcpp::Map<std::string,DiskFile>::iterator, bool> addCacheEntry(const std::string& relativePath, const boost::filesystem::path& filePath, const bool placeholder);
		void sendNotFoundResponse(pion::net::HTTPRequestPtr& httpRequest, pion::net::TCPConnectionPtr& tcpConn);
};


}

#endif
